package com.aryankh.service.impl;

import com.aryankh.configuration.CustomObjectMapper;
import com.aryankh.constant.Constants;
import com.aryankh.core.RedisTemplate;
import com.aryankh.entity.KhLoginUser;
import com.aryankh.entity.KhMenu;
import com.aryankh.entity.KhRole;
import com.aryankh.entity.KhUser;
import com.aryankh.dao.KhUserDao;
import com.aryankh.exception.PasswordIncorrectException;
import com.aryankh.exception.UserNotFoundException;
import com.aryankh.service.KhUserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户信息表(KhUser)表服务实现类
 *
 * @author makejava
 * @since 2022-05-28 07:19:51
 */
@Slf4j
@Service("khUserService")
public class KhUserServiceImpl implements KhUserService {
    @Resource
    private KhUserDao khUserDao;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private CustomObjectMapper objectMapper;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 通过ID查询单条数据
     *
     * @param userId 主键
     * @return 实例对象
     */
    @Override
    public KhUser queryById(Long userId) {
        return this.khUserDao.queryById(userId);
    }

    /**
     * 分页查询
     *
     * @param khUser      筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    @Override
    public Page<KhUser> queryByPage(KhUser khUser, PageRequest pageRequest) {
        long total = this.khUserDao.count(khUser);
        return new PageImpl<>(this.khUserDao.queryAllByLimit(khUser, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param khUser 实例对象
     * @return 实例对象
     */
    @Override
    public KhUser insert(KhUser khUser) {
        this.khUserDao.insert(khUser);
        return khUser;
    }

    /**
     * 修改数据
     *
     * @param khUser 实例对象
     * @return 实例对象
     */
    @Override
    public KhUser update(KhUser khUser) {
        this.khUserDao.update(khUser);
        return this.queryById(khUser.getUserId());
    }

    /**
     * 通过主键删除数据
     *
     * @param userId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long userId) {
        return this.khUserDao.deleteById(userId) > 0;
    }

    @Override
    public KhLoginUser login(String userName, String password) throws JsonProcessingException {

        // 登录, 使用用户名查询用户,没有查询到 所没有该用户
        KhUser khUser = khUserDao.queryByUserName(userName);
        if (khUser == null) {
            throw new UserNotFoundException("登录操作:" + userName + "该用户不存在");
        }
        // 登录, 使用用户名查询用户,如果查询到则比较密码 如果密码不正确则登录失败
        if (!password.equals(khUser.getPassword())) {
            log.info("登录操作:" + userName + "该用户密码错误");
            throw new PasswordIncorrectException("登录操作:" + userName + "该用户密码错误");
        }
        //如果验证成功
        //1. 生成token
        String token = UUID.randomUUID().toString();
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        UserAgent userAgent = new UserAgent(request.getHeader("User-Agent"));
        //通过ip获取其所属的地址
        ResponseEntity<String> forEntity = restTemplate.getForEntity("https://whois.pconline.com.cn/ipJson.jsp?ip=172.18.1.21&json=true", String.class);
        String body = forEntity.getBody();
        Map<String, String> map = objectMapper.readValue(body, new TypeReference<>() {
        });

        String loacation = (map.get("addr") + map.get("pro") + map.get("city") + map.get("region"));

        //2.封装一个登录用户 KhLoginUser 保存在redis
        KhLoginUser khLoginUser = KhLoginUser.builder().userId(khUser.getUserId()).token(token).ipaddr(request.getRemoteAddr()).loginTime(new Date()).loginLocation(loacation).browser(userAgent.getBrowser().getName()).os(String.valueOf(userAgent.getOperatingSystem())).khUser(khUser).build();
        //对key 进行处理 token:username:username
        //1.根据用户名生成的key的前缀 进行判断  token:username
        String keyPrefix = Constants.TOKEN_PREFIX + userName + ":";
        //2.查询 token:username:前缀的数据
        Set<String> keys = redisTemplate.keys(keyPrefix + "*");
        //3.删除原来的key
        keys.forEach(key -> {
            redisTemplate.remove(key);
        });
        //4.把新的数据加入
        redisTemplate.setObject(keyPrefix + token, khLoginUser, Constants.TOKEN_TIME);
        return khLoginUser;
    }

    @Override
    public void logout() {
        //删除redis中的token user这些数据
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        //获取首部信息的token
        String token = request.getHeader(Constants.AUTHORIZATION);
        long remove = redisTemplate.remove("token." + Constants.TOKEN_PREFIX + token);
    }

    @Override
    public HashMap<String, List<String>> getInfo() {
        // 获取当前登录的对象
        KhLoginUser loginUser = getLoginUser();
        // 查询当前用户的角色和权限
        KhUser info = khUserDao.getInfo(loginUser.getUserId());


        // 处理角色的相关信息
        // roles:token:[admin,xxx,yyy] prems:token: [system:user:add,system:user:update]
        List<String> roleTags = info.getKhRoles().stream().map(KhRole::getRoleTag).collect(Collectors.toList());
        redisTemplate.setObject(Constants.ROLE_PREFIX + loginUser.getToken(), roleTags, Constants.TOKEN_TIME);
        List<String> premsTags = new ArrayList<>();
        info.getKhRoles().stream().map(KhRole::getKhMenus).forEach(menus -> {
            premsTags.addAll(menus.stream().map(KhMenu::getPerms).collect(Collectors.toList()));
        });
        redisTemplate.setObject(Constants.PERM_PREFIX+loginUser.getToken(),premsTags,Constants.TOKEN_TIME);


        //整合数据
        HashMap<String, List<String>> data = new HashMap<>(64);
        data.put("roles",roleTags);
        data.put("prems",premsTags);
        return data;
    }

    private KhLoginUser getLoginUser() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        //获取首部信息的token
        String token = request.getHeader(Constants.AUTHORIZATION);
        // String tokenKey=Constants.TOKEN_PREFIX+request.getHeader("username")+":"+token;
        //先判断有无Authorization 拿到首部信息 Authorization 的值
        if (token == null) {
            throw new RuntimeException("当前用户未登录");
        }
        Set<String> keys = redisTemplate.keys(Constants.TOKEN_PREFIX + "*" + token);
        if (keys == null || keys.size() == 0) {
            throw new RuntimeException("当前用户未登录");
        }
        String tokenKey = (String) keys.toArray()[0];
        //使用token去redis中查看有无对应的loginUser
        return redisTemplate.getObject(tokenKey, new TypeReference<KhLoginUser>() {
        });
    }

    public static void main(String[] args) {
        //使用java 发送http请求
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> forEntity = restTemplate.getForEntity("https://whois.pconline.com.cn/ipJson.jsp?ip=172.18.1.21&json=true", String.class);
        System.out.println(forEntity.getBody());

    }
}
